home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / MAME / src / cpu / m6502 / m65ce02.c < prev    next >
C/C++ Source or Header  |  2000-05-08  |  12KB  |  428 lines

  1. /*****************************************************************************
  2.  *
  3.  *     m65ce02.c
  4.  *     Portable 65ce02 emulator V1.0beta3
  5.  *
  6.  *     Copyright (c) 2000 Peter Trauner, all rights reserved
  7.  *   documentation preliminary databook
  8.  *     documentation by michael steil mist@c64.org
  9.  *     available at ftp://ftp.funet.fi/pub/cbm/c65
  10.  *
  11.  *     - This source code is released as freeware for non-commercial purposes.
  12.  *     - You are free to use and redistribute this code in modified or
  13.  *       unmodified form, provided you list me in the credits.
  14.  *     - If you modify this source code, you must add a notice to each modified
  15.  *       source file that it has been changed.  If you're a nice person, you
  16.  *       will clearly mark each change too.  :)
  17.  *     - If you wish to use this for commercial purposes, please contact me at
  18.  *       pullmoll@t-online.de
  19.  *     - The author of this copywritten work reserves the right to change the
  20.  *       terms of its usage and license at any time, including retroactively
  21.  *     - This entire notice must remain in the source code.
  22.  *
  23.  *****************************************************************************/
  24. /* 4. February 2000 PeT fixed relative word operand */
  25. /* 4. February 2000 PeT jsr (absolut) jsr (absolut,x) inw dew */
  26. /* 17.February 2000 PeT phw */
  27. /* 16.March 2000 PeT fixed some instructions accordingly to databook */
  28. /* 7. May 2000 PeT splittet into m65ce02 and m4510 */
  29.  
  30. /*
  31.  
  32. * neg is now simple 2er komplement negation with set of N and Z
  33.  
  34. * phw push low order byte, push high order byte!
  35.  
  36. * tys txs not interruptable, not implemented
  37.  
  38. */
  39.  
  40. #include <stdio.h>
  41. #include "driver.h"
  42. #include "state.h"
  43. #include "mamedbg.h"
  44. #include "m65ce02.h"
  45.  
  46. #include "ops02.h"
  47. #include "opsc02.h"
  48. #include "opsce02.h"
  49.  
  50. #define VERBOSE 0
  51.  
  52. #if VERBOSE
  53. #define LOG(x)    logerror x
  54. #else
  55. #define LOG(x)
  56. #endif
  57.  
  58. /* Layout of the registers in the debugger */
  59. static UINT8 m65ce02_reg_layout[] = {
  60.     M65CE02_A,M65CE02_X,M65CE02_Y,M65CE02_Z,M65CE02_S,M65CE02_PC,
  61.     M65CE02_P, 
  62.     -1,
  63.     M65CE02_EA,M65CE02_ZP,M65CE02_NMI_STATE,M65CE02_IRQ_STATE, M65CE02_B,
  64.     0
  65. };
  66.  
  67. /* Layout of the debugger windows x,y,w,h */
  68. static UINT8 m65ce02_win_layout[] = {
  69.     25, 0,55, 2,    /* register window (top, right rows) */
  70.      0, 0,24,22,    /* disassembler window (left colums) */
  71.     25, 3,55, 9,    /* memory #1 window (right, upper middle) */
  72.     25,13,55, 9,    /* memory #2 window (right, lower middle) */
  73.      0,23,80, 1,    /* command line window (bottom rows) */
  74. };
  75.  
  76. typedef struct {
  77.     void    (**insn)(void); /* pointer to the function pointer table */
  78.     PAIR    ppc;            /* previous program counter */
  79.     PAIR    pc;             /* program counter */
  80.     PAIR    sp;             /* stack pointer (always 100 - 1FF) */
  81.     PAIR    zp;             /* zero page address */
  82.     /* contains B register zp.b.h */
  83.     PAIR    ea;             /* effective address */
  84.     UINT8    a;                /* Accumulator */
  85.     UINT8    x;                /* X index register */
  86.     UINT8    y;                /* Y index register */
  87.     UINT8    z;                /* Z index register */
  88.     UINT8    p;                /* Processor status */
  89.     UINT8    pending_irq;    /* nonzero if an IRQ is pending */
  90.     UINT8    after_cli;        /* pending IRQ and last insn cleared I */
  91.     UINT8    nmi_state;
  92.     UINT8    irq_state;
  93.     int     (*irq_callback)(int irqline);    /* IRQ callback */
  94. }    m65ce02_Regs;
  95.  
  96.  
  97. int m65ce02_ICount = 0;
  98.  
  99. static m65ce02_Regs m65ce02;
  100.  
  101. /***************************************************************
  102.  * include the opcode macros, functions and tables
  103.  ***************************************************************/
  104.  
  105. #include "t65ce02.c"
  106.  
  107. void m65ce02_reset (void *param)
  108. {
  109.     m65ce02.insn = insn65ce02;
  110.  
  111.     /* wipe out the rest of the m65ce02 structure */
  112.     /* read the reset vector into PC */
  113.     /* reset z index and b bank */
  114.     PCL = RDMEM(M65CE02_RST_VEC);
  115.     PCH = RDMEM(M65CE02_RST_VEC+1);
  116.  
  117.     /* after reset in 6502 compatibility mode */
  118.     m65ce02.sp.d = 0x01ff; /* high byte descriped in databook */
  119.     m65ce02.z = 0;
  120.     B = 0;
  121.     m65ce02.p = F_E|F_B|F_I|F_Z;    /* set E, I and Z flags */
  122.     m65ce02.pending_irq = 0;    /* nonzero if an IRQ is pending */
  123.     m65ce02.after_cli = 0;        /* pending IRQ and last insn cleared I */
  124.     m65ce02.irq_callback = NULL;
  125.  
  126.     change_pc16(PCD);
  127. }
  128.  
  129. void m65ce02_exit(void)
  130. {
  131.     /* nothing to do yet */
  132. }
  133.  
  134. unsigned m65ce02_get_context (void *dst)
  135. {
  136.     if( dst )
  137.         *(m65ce02_Regs*)dst = m65ce02;
  138.     return sizeof(m65ce02_Regs);
  139. }
  140.  
  141. void m65ce02_set_context (void *src)
  142. {
  143.     if( src )
  144.     {
  145.         m65ce02 = *(m65ce02_Regs*)src;
  146.         change_pc16(PCD);
  147.     }
  148. }
  149.  
  150. unsigned m65ce02_get_pc (void)
  151. {
  152.     return PCD;
  153. }
  154.  
  155. void m65ce02_set_pc (unsigned val)
  156. {
  157.     PCW = val;
  158.     change_pc16(PCD);
  159. }
  160.  
  161. unsigned m65ce02_get_sp (void)
  162. {
  163.     return S;
  164. }
  165.  
  166. void m65ce02_set_sp (unsigned val)
  167. {
  168.     S = val;
  169. }
  170.  
  171. unsigned m65ce02_get_reg (int regnum)
  172. {
  173.     switch( regnum )
  174.     {
  175.         case M65CE02_PC: return m65ce02.pc.w.l;
  176.         case M65CE02_S: return m65ce02.sp.w.l;
  177.         case M65CE02_P: return m65ce02.p;
  178.         case M65CE02_A: return m65ce02.a;
  179.         case M65CE02_X: return m65ce02.x;
  180.         case M65CE02_Y: return m65ce02.y;
  181.         case M65CE02_Z: return m65ce02.z;
  182.         case M65CE02_B: return m65ce02.zp.b.h;
  183.         case M65CE02_EA: return m65ce02.ea.w.l;
  184.         case M65CE02_ZP: return m65ce02.zp.b.l;
  185.         case M65CE02_NMI_STATE: return m65ce02.nmi_state;
  186.         case M65CE02_IRQ_STATE: return m65ce02.irq_state;
  187.         case REG_PREVIOUSPC: return m65ce02.ppc.w.l;
  188.         default:
  189.             if( regnum <= REG_SP_CONTENTS )
  190.             {
  191.                 unsigned offset = S + 2 * (REG_SP_CONTENTS - regnum);
  192.                 if( offset < 0x1ff )
  193.                     return RDMEM( offset ) | ( RDMEM( offset + 1 ) << 8 );
  194.             }
  195.     }
  196.     return 0;
  197. }
  198.  
  199. void m65ce02_set_reg (int regnum, unsigned val)
  200. {
  201.     switch( regnum )
  202.     {
  203.         case M65CE02_PC: m65ce02.pc.w.l = val; break;
  204.         case M65CE02_S: m65ce02.sp.w.l = val; break;
  205.         case M65CE02_P: m65ce02.p = val; break;
  206.         case M65CE02_A: m65ce02.a = val; break;
  207.         case M65CE02_X: m65ce02.x = val; break;
  208.         case M65CE02_Y: m65ce02.y = val; break;
  209.         case M65CE02_Z: m65ce02.z = val; break;
  210.         case M65CE02_B: m65ce02.zp.b.h = val; break;
  211.         case M65CE02_EA: m65ce02.ea.w.l = val; break;
  212.         case M65CE02_ZP: m65ce02.zp.b.l = val; break;
  213.         case M65CE02_NMI_STATE: m65ce02_set_nmi_line( val ); break;
  214.         case M65CE02_IRQ_STATE: m65ce02_set_irq_line( 0, val ); break;
  215.         default:
  216.             if( regnum <= REG_SP_CONTENTS )
  217.             {
  218.                 unsigned offset = S + 2 * (REG_SP_CONTENTS - regnum);
  219.                 if( offset < 0x1ff )
  220.                 {
  221.                     WRMEM( offset, val & 0xfff );
  222.                     WRMEM( offset + 1, (val >> 8) & 0xff );
  223.                 }
  224.             }
  225.     }
  226. }
  227.  
  228. INLINE void m65ce02_take_irq(void)
  229. {
  230.     if( !(P & F_I) )
  231.     {
  232.         EAD = M65CE02_IRQ_VEC;
  233.         m65ce02_ICount -= 7;
  234.         PUSH(PCH);
  235.         PUSH(PCL);
  236.         PUSH(P & ~F_B);
  237.         P = (P & ~F_D) | F_I;        /* knock out D and set I flag */
  238.         PCL = RDMEM(EAD);
  239.         PCH = RDMEM(EAD+1);
  240.         LOG(("M65ce02#%d takes IRQ ($%04x)\n", cpu_getactivecpu(), PCD));
  241.         /* call back the cpuintrf to let it clear the line */
  242.         if (m65ce02.irq_callback) (*m65ce02.irq_callback)(0);
  243.         change_pc16(PCD);
  244.     }
  245.     m65ce02.pending_irq = 0;
  246. }
  247.  
  248. int m65ce02_execute(int cycles)
  249. {
  250.     m65ce02_ICount = cycles;
  251.  
  252.     change_pc16(PCD);
  253.  
  254.     do
  255.     {
  256.         UINT8 op;
  257.         PPC = PCD;
  258.  
  259.         CALL_MAME_DEBUG;
  260.  
  261.         /* if an irq is pending, take it now */
  262.         if( m65ce02.pending_irq )
  263.             m65ce02_take_irq();
  264.  
  265.         op = RDOP();
  266.         (*insn65ce02[op])();
  267.  
  268.         /* check if the I flag was just reset (interrupts enabled) */
  269.         if( m65ce02.after_cli )
  270.         {
  271.             LOG(("M65ce02#%d after_cli was >0", cpu_getactivecpu()));
  272.             m65ce02.after_cli = 0;
  273.             if (m65ce02.irq_state != CLEAR_LINE)
  274.             {
  275.                 LOG((": irq line is asserted: set pending IRQ\n"));
  276.                 m65ce02.pending_irq = 1;
  277.             }
  278.             else
  279.             {
  280.                 LOG((": irq line is clear\n"));
  281.             }
  282.         }
  283.         else
  284.         if( m65ce02.pending_irq )
  285.             m65ce02_take_irq();
  286.  
  287.     } while (m65ce02_ICount > 0);
  288.  
  289.     return cycles - m65ce02_ICount;
  290. }
  291.  
  292. void m65ce02_set_nmi_line(int state)
  293. {
  294.     if (m65ce02.nmi_state == state) return;
  295.     m65ce02.nmi_state = state;
  296.     if( state != CLEAR_LINE )
  297.     {
  298.         LOG(("M65ce02#%d set_nmi_line(ASSERT)\n", cpu_getactivecpu()));
  299.         EAD = M65CE02_NMI_VEC;
  300.         m65ce02_ICount -= 7;
  301.         PUSH(PCH);
  302.         PUSH(PCL);
  303.         PUSH(P & ~F_B);
  304.         P = (P & ~F_D) | F_I;        /* knock out D and set I flag */
  305.         PCL = RDMEM(EAD);
  306.         PCH = RDMEM(EAD+1);
  307.         LOG(("M65ce02#%d takes NMI ($%04x)\n", cpu_getactivecpu(), PCD));
  308.         change_pc16(PCD);
  309.     }
  310. }
  311.  
  312. void m65ce02_set_irq_line(int irqline, int state)
  313. {
  314.     m65ce02.irq_state = state;
  315.     if( state != CLEAR_LINE )
  316.     {
  317.         LOG(("M65ce02#%d set_irq_line(ASSERT)\n", cpu_getactivecpu()));
  318.         m65ce02.pending_irq = 1;
  319.     }
  320. }
  321.  
  322. void m65ce02_set_irq_callback(int (*callback)(int))
  323. {
  324.     m65ce02.irq_callback = callback;
  325. }
  326.  
  327. void m65ce02_state_save(void *file)
  328. {
  329.     int cpu = cpu_getactivecpu();
  330.     /* insn is set at restore since it's a pointer */
  331.     state_save_UINT16(file,"m65ce02",cpu,"PC",&m65ce02.pc.w.l,2);
  332.     state_save_UINT16(file,"m65ce02",cpu,"SP",&m65ce02.sp.w.l,2);
  333.     state_save_UINT8(file,"m65ce02",cpu,"P",&m65ce02.p,1);
  334.     state_save_UINT8(file,"m65ce02",cpu,"A",&m65ce02.a,1);
  335.     state_save_UINT8(file,"m65ce02",cpu,"X",&m65ce02.x,1);
  336.     state_save_UINT8(file,"m65ce02",cpu,"Y",&m65ce02.y,1);
  337.     state_save_UINT8(file,"m65ce02",cpu,"Z",&m65ce02.z,1);
  338.     state_save_UINT8(file,"m65ce02",cpu,"B",&m65ce02.zp.b.h,1);
  339.     state_save_UINT8(file,"m65ce02",cpu,"PENDING",&m65ce02.pending_irq,1);
  340.     state_save_UINT8(file,"m65ce02",cpu,"AFTER_CLI",&m65ce02.after_cli,1);
  341.     state_save_UINT8(file,"m65ce02",cpu,"NMI_STATE",&m65ce02.nmi_state,1);
  342.     state_save_UINT8(file,"m65ce02",cpu,"IRQ_STATE",&m65ce02.irq_state,1);
  343. }
  344.  
  345. void m65ce02_state_load(void *file)
  346. {
  347.     int cpu = cpu_getactivecpu();
  348.     m65ce02.insn = insn65ce02;
  349.     state_load_UINT16(file,"m65ce02",cpu,"PC",&m65ce02.pc.w.l,2);
  350.     state_load_UINT16(file,"m65ce02",cpu,"SP",&m65ce02.sp.w.l,2);
  351.     state_load_UINT8(file,"m65ce02",cpu,"P",&m65ce02.p,1);
  352.     state_load_UINT8(file,"m65ce02",cpu,"A",&m65ce02.a,1);
  353.     state_load_UINT8(file,"m65ce02",cpu,"X",&m65ce02.x,1);
  354.     state_load_UINT8(file,"m65ce02",cpu,"Y",&m65ce02.y,1);
  355.     state_load_UINT8(file,"m65ce02",cpu,"Z",&m65ce02.z,1);
  356.     state_load_UINT8(file,"m65ce02",cpu,"B",&m65ce02.zp.b.h,1);
  357.     state_load_UINT8(file,"m65ce02",cpu,"PENDING",&m65ce02.pending_irq,1);
  358.     state_load_UINT8(file,"m65ce02",cpu,"AFTER_CLI",&m65ce02.after_cli,1);
  359.     state_load_UINT8(file,"m65ce02",cpu,"NMI_STATE",&m65ce02.nmi_state,1);
  360.     state_load_UINT8(file,"m65ce02",cpu,"IRQ_STATE",&m65ce02.irq_state,1);
  361. }
  362.  
  363. /****************************************************************************
  364.  * Return a formatted string for a register
  365.  ****************************************************************************/
  366. const char *m65ce02_info(void *context, int regnum)
  367. {
  368.     static char buffer[16][47+1];
  369.     static int which = 0;
  370.     m65ce02_Regs *r = context;
  371.  
  372.     which = ++which % 16;
  373.     buffer[which][0] = '\0';
  374.     if( !context )
  375.         r = &m65ce02;
  376.  
  377.     switch( regnum )
  378.     {
  379.         case CPU_INFO_REG+M65CE02_PC: sprintf(buffer[which], "PC:%04X", r->pc.w.l); break;
  380.         case CPU_INFO_REG+M65CE02_S: sprintf(buffer[which], "S:%04X", r->sp.w.l); break;
  381.         case CPU_INFO_REG+M65CE02_P: sprintf(buffer[which], "P:%02X", r->p); break;
  382.         case CPU_INFO_REG+M65CE02_A: sprintf(buffer[which], "A:%02X", r->a); break;
  383.         case CPU_INFO_REG+M65CE02_X: sprintf(buffer[which], "X:%02X", r->x); break;
  384.         case CPU_INFO_REG+M65CE02_Y: sprintf(buffer[which], "Y:%02X", r->y); break;
  385.         case CPU_INFO_REG+M65CE02_Z: sprintf(buffer[which], "Z:%02X", r->z); break;
  386.         case CPU_INFO_REG+M65CE02_B: sprintf(buffer[which], "B:%02X", r->zp.b.h); break;
  387.         case CPU_INFO_REG+M65CE02_EA: sprintf(buffer[which], "EA:%04X", r->ea.w.l); break;
  388.         case CPU_INFO_REG+M65CE02_ZP: sprintf(buffer[which], "ZP:%04X", r->zp.w.l); break;
  389.         case CPU_INFO_REG+M65CE02_NMI_STATE: sprintf(buffer[which], "NMI:%X", r->nmi_state); break;
  390.         case CPU_INFO_REG+M65CE02_IRQ_STATE: sprintf(buffer[which], "IRQ:%X", r->irq_state); break;
  391.         case CPU_INFO_FLAGS:
  392.             sprintf(buffer[which], "%c%c%c%c%c%c%c%c",
  393.                 r->p & 0x80 ? 'N':'.',
  394.                 r->p & 0x40 ? 'V':'.',
  395.                 r->p & 0x20 ? 'E':'.',
  396.                 r->p & 0x10 ? 'B':'.',
  397.                 r->p & 0x08 ? 'D':'.',
  398.                 r->p & 0x04 ? 'I':'.',
  399.                 r->p & 0x02 ? 'Z':'.',
  400.                 r->p & 0x01 ? 'C':'.');
  401.             break;
  402.         case CPU_INFO_NAME: return "M65CE02";
  403.         case CPU_INFO_FAMILY: return "CBM Semiconductor Group CSG 65CE02";
  404.         case CPU_INFO_VERSION: return "1.0beta";
  405.         case CPU_INFO_CREDITS:
  406.             return "Copyright (c) 1998 Juergen Buchmueller\n"
  407.                 "Copyright (c) 2000 Peter Trauner\n"
  408.                 "all rights reserved.";
  409.         case CPU_INFO_FILE: return __FILE__;
  410.         case CPU_INFO_REG_LAYOUT: return (const char*)m65ce02_reg_layout;
  411.         case CPU_INFO_WIN_LAYOUT: return (const char*)m65ce02_win_layout;
  412.     }
  413.     return buffer[which];
  414. }
  415.  
  416. unsigned int m65ce02_dasm(char *buffer, unsigned pc)
  417. {
  418. #ifdef MAME_DEBUG
  419.     return Dasm65ce02( buffer, pc );
  420. #else
  421.     sprintf( buffer, "$%02X", cpu_readop(pc) );
  422.     return 1;
  423. #endif
  424. }
  425.  
  426.  
  427.  
  428.